package com.example.concurrent;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.locks.Lock;

/**
 * @author houyangfan
 * @version 1.0
 * @date 2022/10/2 20:12
 * <p>
 * 该类用于演示多线程运行期间栈帧使用的演示
 */
@Slf4j
public class MultiThreadRunTest {

    public static int amount = 1000;

    public static void main(String[] args) throws InterruptedException {
        // 新建一个线程调用method1方法
        // 这里需要注意的是打断点的时候要使用Thread模式
        /*Thread thread = new Thread("t1"){
            @Override
            public void run() {
                int count = 0;
               for (;;){
                   System.out.println("------>" + count++);
                }
            }
        };
        FutureTask<Integer> futureTask = new FutureTask(()->{
            int count = 0;
            for (;;){
                System.out.println("        ------>"+ count++);
            }
        });
        thread.start();
        Thread thread1 = new Thread(futureTask);
        thread1.start();*/
        // 主线程调用menthod1 方法
        // 程序运行后，主线程会先调用这里,此时t1线程和主线程都是Running状态
        //method1(10);

//        Thread thread = new Thread("t1"){
//            @Override
//            public void run() {
//                System.out.println(Thread.currentThread().getName()+"开始");
//                try {
//                    TimeUnit.SECONDS.sleep(2);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                count = 10;
//                System.out.println(Thread.currentThread().getName()+"结束");
//            }
//        };
//        thread.start();
//        thread.join(1000);
//        System.out.println("结果："+count);
//        System.out.println(Thread.currentThread().getName()+"结束");


        //todo 演示线程的六种状态
        testStatusShow();

        // 泡茶的工作
        //testMakeTea();

        //new MultiThreadRunTest().testSync();

        // todo 卖票问题
        // 假设有2000个人在抢票
        /*MultiThreadRunTest m = new MultiThreadRunTest();
        List<Integer> selledList = new ArrayList<>();
        for (int i = 0; i < 2000; i++) {
            Thread thread = new Thread(()->{
                int count = m.getRandom();
                int sell = m.sell(count);
                synchronized (m){
                    selledList.add(sell);
                }
            });
            thread.start();
        }

        System.out.println("卖出票数："+ selledList.stream().mapToInt(o -> Objects.isNull(o) ? 0 : o).sum());
        System.out.println("剩余票数："+ amount);*/

        /*MultiThreadRunTest m = new MultiThreadRunTest();
        new Thread(()->{m.b();}).start();
        new Thread(()->{
            try {
                m.a();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();*/
    }

    public int getRandom(){
        Random random = new Random();
        return random.nextInt(5)+1;
    }
    public static void method1(int x) {
        int y = x + 10;
        Object o = method2();
        System.out.println(o);
    }

    public static Object method2() {
        Object o = new Object();
        return o;
    }

    // 线程状态的演示
    public static void testStatusShow() {

        // 定义一个线程但是不开启所以未与操作系统交互
        Thread thread1 = new Thread() {
            @Override
            public void run() {

            }
        };

        // runnable
        Thread thread2 = new Thread() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        thread2.start();

        // TERMINATED
        Thread thread3 = new Thread() {
            @Override
            public void run() {

            }
        };
        thread3.start();

        // timed_waiting
        Thread thread4 = new Thread() {
            @Override
            public void run() {
                synchronized (MultiThreadRunTest.class) {
                    try {
                        TimeUnit.SECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread4.start();

        // waiting 等待thread2执行完再执行 但是thread2一直死循环
        Thread thread5 = new Thread() {
            @SneakyThrows
            @Override
            public void run() {
                    synchronized (MultiThreadRunTest.class){
                        this.wait();
                    }
                    while (true){}
            }
        };
        thread5.start();

        // TERMINATED
        Thread thread6 = new Thread() {
            @Override
            public void run() {
                synchronized (MultiThreadRunTest.class) {
                    System.out.println("执行thread6");
                }
            }
        };
        thread6.start();

        log.info("thread1-status{}", thread1.getState());
        log.info("thread2-status{}", thread2.getState());
        log.info("thread3-status{}", thread3.getState());
        log.info("thread4-status{}", thread4.getState());
        log.info("thread5-status{}", thread5.getState());

        log.info("thread6-status{}", thread6.getState());

        try {
            TimeUnit.SECONDS.sleep(10);
            log.info("thread5-status{}", thread5.getState());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    // 统筹学 用茶壶泡茶的例子
    // todo 开启两个线程 thread1 做洗水壶，烧水的工作，thread2 做 洗茶壶 拿茶叶 洗茶叶 的工作
    public static void testMakeTea() {
        long l1 = System.currentTimeMillis();
        Runnable runnable1 = () -> {
            try {
                TimeUnit.SECONDS.sleep(3);  // 3秒洗水壶
                TimeUnit.SECONDS.sleep(5);  // 5秒模拟烧水
                System.out.println("烧水完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Runnable runnable2 = () -> {
            try {
                TimeUnit.SECONDS.sleep(1);  // 1秒洗茶壶
                TimeUnit.SECONDS.sleep(2);  // 2秒拿茶叶
                TimeUnit.SECONDS.sleep(3);  // 3秒洗茶叶
                System.out.println("茶叶准备完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        long l2 = System.currentTimeMillis();

        Thread thread1 = new Thread(runnable1);
        Thread thread2 = new Thread(runnable2);

        thread1.start();
        thread2.start();
    }

    // todo 对synchoized的使用案例
    private Object object = new Object();
    static int count = 0;

    public void testSync() {

        Thread thread1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    synchronized (object) {
                        count++;
                    }
                }
            }
        };

        Thread thread2 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    synchronized (object) {
                        count--;
                    }
                }
            }
        };

        thread1.start();
        thread2.start();
        System.out.println(count);
    }
    public static synchronized void a() throws InterruptedException {
        System.out.println("1");
    }
    public synchronized void b(){
        System.out.println("2");
    }


    //卖票问题
    public synchronized int sell(int count){
        if (amount >= count) {
            amount -= count;
            return count;
        } else {
            return 0;
        }
    }

}
